package tidb

import (
	"douhu_backend/internal/dao"
	"douhu_backend/internal/model/auth"
	"time"

	"gorm.io/gorm"
)

// AuthTiDBDAO TiDB实现的认证DAO
type AuthTiDBDAO struct {
	db *gorm.DB
}

// NewAuthDAO 创建AuthDAO实例（工厂方法）
func NewAuthDAO(db *gorm.DB) dao.AuthDAO {
	return &AuthTiDBDAO{db: db}
}

// User operations

// CreateUser 创建用户
func (d *AuthTiDBDAO) CreateUser(user *auth.User) error {
	return d.db.Create(user).Error
}

// GetUserByID 根据ID获取用户
func (d *AuthTiDBDAO) GetUserByID(id uint64) (*auth.User, error) {
	var user auth.User
	err := d.db.Where("id = ?", id).First(&user).Error
	if err != nil {
		return nil, err
	}
	return &user, nil
}

// GetUserByPhone 根据手机号获取用户
func (d *AuthTiDBDAO) GetUserByPhone(phone string) (*auth.User, error) {
	var user auth.User
	err := d.db.Where("phone = ?", phone).First(&user).Error
	if err != nil {
		return nil, err
	}
	return &user, nil
}

// GetUserByUsername 根据用户名获取用户
func (d *AuthTiDBDAO) GetUserByUsername(username string) (*auth.User, error) {
	var user auth.User
	err := d.db.Where("username = ?", username).First(&user).Error
	if err != nil {
		return nil, err
	}
	return &user, nil
}

// GetUserByWechatOpenID 根据微信OpenID获取用户
func (d *AuthTiDBDAO) GetUserByWechatOpenID(openID string) (*auth.User, error) {
	var user auth.User
	err := d.db.Where("wechat_open_id = ?", openID).First(&user).Error
	if err != nil {
		return nil, err
	}
	return &user, nil
}

// GetUserByDouyinUID 根据抖音UID获取用户
func (d *AuthTiDBDAO) GetUserByDouyinUID(uid string) (*auth.User, error) {
	var user auth.User
	err := d.db.Where("douyin_uid = ?", uid).First(&user).Error
	if err != nil {
		return nil, err
	}
	return &user, nil
}

// UpdateUser 更新用户信息
func (d *AuthTiDBDAO) UpdateUser(user *auth.User) error {
	return d.db.Save(user).Error
}

// UpdateUserProfile 更新用户个人资料
func (d *AuthTiDBDAO) UpdateUserProfile(userID uint64, updateData map[string]interface{}) error {
	return d.db.Model(&auth.User{}).
		Where("id = ?", userID).
		Updates(updateData).Error
}

// UpdateUserLastLogin 更新用户最后登录信息
func (d *AuthTiDBDAO) UpdateUserLastLogin(userID uint64, ip string, loginTime time.Time) error {
	return d.db.Model(&auth.User{}).
		Where("id = ?", userID).
		Updates(map[string]interface{}{
			"last_login_ip":   ip,
			"last_login_time": loginTime,
		}).Error
}

// UpdateUserRefreshToken 更新用户的refresh token
func (d *AuthTiDBDAO) UpdateUserRefreshToken(userID uint64, refreshToken string, expiresAt time.Time) error {
	return d.db.Model(&auth.User{}).
		Where("id = ?", userID).
		Updates(map[string]interface{}{
			"refresh_token":        refreshToken,
			"refresh_token_exp_at": expiresAt,
		}).Error
}

// ValidateRefreshToken 验证refresh token是否有效
func (d *AuthTiDBDAO) ValidateRefreshToken(userID uint64, refreshToken string) (bool, error) {
	var user auth.User
	err := d.db.Where("id = ? AND refresh_token = ? AND refresh_token_exp_at > ?",
		userID, refreshToken, time.Now()).
		First(&user).Error

	if err == gorm.ErrRecordNotFound {
		return false, nil
	}
	if err != nil {
		return false, err
	}
	return true, nil
}

// SMS code operations

// CreateSMSCode 创建短信验证码
func (d *AuthTiDBDAO) CreateSMSCode(smsCode *auth.SMSCode) error {
	return d.db.Create(smsCode).Error
}

// GetValidSMSCode 获取有效的短信验证码
func (d *AuthTiDBDAO) GetValidSMSCode(phone string, codeType int) (*auth.SMSCode, error) {
	var smsCode auth.SMSCode
	err := d.db.Where("phone = ? AND code_type = ? AND used_status = ? AND expire_time > ?",
		phone, codeType, auth.SMSCodeUnused, time.Now()).
		Order("create_time DESC").
		First(&smsCode).Error
	if err != nil {
		return nil, err
	}
	return &smsCode, nil
}

// MarkSMSCodeUsed 标记短信验证码为已使用
func (d *AuthTiDBDAO) MarkSMSCodeUsed(id uint64, usedTime time.Time) error {
	return d.db.Model(&auth.SMSCode{}).
		Where("id = ?", id).
		Updates(map[string]interface{}{
			"used_status": auth.SMSCodeUsed,
			"used_time":   &usedTime,
		}).Error
}

// CleanExpiredSMSCodes 清理过期的短信验证码
func (d *AuthTiDBDAO) CleanExpiredSMSCodes() error {
	return d.db.Where("expire_time < ?", time.Now()).Delete(&auth.SMSCode{}).Error
}

// GetSMSCodeSendCount 获取指定时间段内发送短信验证码的次数
func (d *AuthTiDBDAO) GetSMSCodeSendCount(phone string, duration time.Duration) (int64, error) {
	var count int64
	err := d.db.Model(&auth.SMSCode{}).
		Where("phone = ? AND create_time > ?", phone, time.Now().Add(-duration)).
		Count(&count).Error
	return count, err
}

// Login attempt operations

// CreateLoginAttempt 创建登录尝试记录
func (d *AuthTiDBDAO) CreateLoginAttempt(attempt *auth.LoginAttempt) error {
	return d.db.Create(attempt).Error
}

// GetLoginAttempts 获取指定时间段内的登录尝试记录
func (d *AuthTiDBDAO) GetLoginAttempts(phone string, duration time.Duration) ([]*auth.LoginAttempt, error) {
	var attempts []*auth.LoginAttempt
	err := d.db.Where("phone = ? AND attempt_time > ?", phone, time.Now().Add(-duration)).
		Order("attempt_time DESC").
		Find(&attempts).Error
	return attempts, err
}

// GetFailedLoginCount 获取指定时间段内登录失败次数
func (d *AuthTiDBDAO) GetFailedLoginCount(phone string, duration time.Duration) (int64, error) {
	var count int64
	err := d.db.Model(&auth.LoginAttempt{}).
		Where("phone = ? AND is_success = ? AND attempt_time > ?",
			phone, false, time.Now().Add(-duration)).
		Count(&count).Error
	return count, err
}

// Login limit operations

// CreateOrUpdateLoginLimit 创建或更新登录限制
func (d *AuthTiDBDAO) CreateOrUpdateLoginLimit(limit *auth.LoginLimit) error {
	var existingLimit auth.LoginLimit
	err := d.db.Where("phone = ?", limit.Phone).First(&existingLimit).Error
	
	if err == gorm.ErrRecordNotFound {
		// 不存在则创建
		return d.db.Create(limit).Error
	} else if err != nil {
		return err
	} else {
		// 存在则更新
		limit.ID = existingLimit.ID
		limit.CreateTime = existingLimit.CreateTime
		return d.db.Save(limit).Error
	}
}

// GetLoginLimit 获取登录限制信息
func (d *AuthTiDBDAO) GetLoginLimit(phone string) (*auth.LoginLimit, error) {
	var limit auth.LoginLimit
	err := d.db.Where("phone = ?", phone).First(&limit).Error
	if err != nil {
		return nil, err
	}
	return &limit, nil
}

// ClearLoginLimit 清除登录限制
func (d *AuthTiDBDAO) ClearLoginLimit(phone string) error {
	return d.db.Where("phone = ?", phone).Delete(&auth.LoginLimit{}).Error
}

// CleanExpiredLoginLimits 清理过期的登录限制
func (d *AuthTiDBDAO) CleanExpiredLoginLimits() error {
	return d.db.Where("lock_exp_time < ?", time.Now()).Delete(&auth.LoginLimit{}).Error
}

// IsRecordNotFound 判断是否为记录不存在错误
func (d *AuthTiDBDAO) IsRecordNotFound(err error) bool {
	return gorm.ErrRecordNotFound == err || err.Error() == gorm.ErrRecordNotFound.Error()
}